package echo.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;

/**
 * @author： zhangnan
 * @date： 2025/4/14 19:19
 * @description： 测试netty使用线程池处理耗时业务逻辑，避免阻塞
 * @modifiedBy：
 * @version: 1.0
 */
public class NettyServerWithAsyncBusiness {

    public static void main(String[] args) throws InterruptedException {
        int port = 8080;
        // 获取当前系统的CPU核心数，后续用于线程池的配置
        int cpuCores = Runtime.getRuntime().availableProcessors();
        // 创建Boss线程组，主要用于处理客户端的连接请求，通常使用线程即可
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // 创建worker线程组，用于处理客户端独写事件。再IO密集型场景下，线程数设置为CUP核心数的2倍
        EventLoopGroup workerGroup = new NioEventLoopGroup(cpuCores * 2);
        System.out.println("线程组数量： " + cpuCores * 2);
        try {
            // 创建业务线程池，用于处理耗时的业务逻辑。在计算密集型场景下，线程数设置为CPU核心数
            final EventExecutorGroup businessGroup = new DefaultEventExecutorGroup(cpuCores);

            // 创建服务器启动引导类，用于配置和启动服务器
            ServerBootstrap b = new ServerBootstrap();
            // 设置服务器使用的线程组，包括 Boss 线程组和 worker 线程组
            b.group(bossGroup, workerGroup)
                    // 指定服务器使用的通道类型为 NioServerSocketChannel,基于NIO实现
                    .channel(NioServerSocketChannel.class)
                    // 为每个新连接的客户端配置ChannelPipeline
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        // 当有新的客户端连接时，会调用此方法初始化 ChannelPipeline
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 获取通道的管道，管道是处理器链，用于处理入站和出站数据
                            ChannelPipeline pipeline = ch.pipeline();
                            // 用于接收到的字节数据解码为字符串
                            pipeline.addLast(new StringDecoder());
                            // 用于将响应的字符串编码为字节数据
                            pipeline.addLast(new StringEncoder());
                            // 指定使用业务线程池来执行该处理器的逻辑
                            pipeline.addLast(businessGroup,"blockingHandler",new BlockingHandler());
//                            pipeline.addLast("blockingHandler", new BlockingHandler());
                        }
                    });

            // 绑定服务器到指定端口，并同步当代绑定完成
            ChannelFuture f = b.bind(port).sync();
            // 打印启动信息,显示监听端口号
            System.out.println("服务器启动，监听端口：" + port);
            // 等待服务器通道关闭，确保服务器一直运行
            f.channel().closeFuture().sync();
        } finally {
            // 优雅的关闭woker线程组
            workerGroup.shutdownGracefully();
            // 优雅的关闭boos线程组
            bossGroup.shutdownGracefully();
        }
    }

}
